namespace Microsoft.VisualStudio.EnterpriseTools.OperationDesigner
{
    using Microsoft.Internal.Performance;
    using Microsoft.VisualStudio.Modeling;
    using Microsoft.VisualStudio.VirtualTreeGrid;
    using System;
    using System.ComponentModel.Design;
    using System.Runtime.CompilerServices;
    using System.Windows.Forms;

    public abstract class OperationDesignerBranch : IServiceProvider, IBranch, IMultiColumnBranch, IOperationDesignerBranch, IOperationDesignerInitializeBranch
    {
        private static bool abortVirtualTreeEdit;
        public const int AppendIndex = -1;
        public static readonly ObjectStyle BrowsingObject = ((ObjectStyle) VirtualTreeConstant.FirstUserObjectStyle);
        private ColumnDescriptor[] columns;
        internal static AccessibilityReplacementField[] descriptionAccessibilityReplacementFields = new AccessibilityReplacementField[] { AccessibilityReplacementField.ColumnHeader, AccessibilityReplacementField.DisplayText, AccessibilityReplacementField.ChildRowCountText, AccessibilityReplacementField.GlobalRowText1, AccessibilityReplacementField.GlobalRowAndColumnText1, AccessibilityReplacementField.StateImageText };
        private bool inCreatorNodeCommit;
        private int insertingCreatorIndex;
        private int insertingIndex;
        private static bool inVirtualTreeEdit;
        private string lastText;
        private bool readOnly;

        private event BranchModificationEventHandler onBranchModification;

        public event BranchModificationEventHandler OnBranchModification
        {
            add
            {
                if (this.onBranchModification == null)
                {
                    this.AddEventHandlers();
                }
                this.onBranchModification = (BranchModificationEventHandler) Delegate.Combine(this.onBranchModification, value);
            }
            remove
            {
                this.onBranchModification = (BranchModificationEventHandler) Delegate.Remove(this.onBranchModification, value);
                if (this.onBranchModification == null)
                {
                    this.RemoveEventHandlers();
                }
            }
        }

        protected OperationDesignerBranch()
        {
            this.insertingIndex = -1;
            this.insertingCreatorIndex = -1;
            this.readOnly = false;
        }

        protected OperationDesignerBranch(ColumnDescriptor[] columns)
        {
            this.insertingIndex = -1;
            this.insertingCreatorIndex = -1;
            if (columns == null)
            {
                throw new ArgumentNullException("columns");
            }
            this.columns = columns;
            this.readOnly = false;
        }

        protected virtual void AddEventHandlers()
        {
        }

        public VirtualTreeLabelEditData BeginLabelEdit(int row, int column, VirtualTreeLabelEditActivationStyles activationStyle)
        {
            string alternateText = null;
            int maxTextLength = 0;
            object customInPlaceEdit = null;
            if (!this.BeginLabelEdit(row, column, ref alternateText, ref maxTextLength, ref customInPlaceEdit))
            {
                return VirtualTreeLabelEditData.Invalid;
            }
            return new VirtualTreeLabelEditData(customInPlaceEdit, null, alternateText, maxTextLength);
        }

        protected virtual bool BeginLabelEdit(int row, int column, ref string alternateText, ref int maxTextLength, ref object customInPlaceEdit)
        {
            AbortVirtualTreeEdit = false;
            if ((this.GetValueSupported(row, column) & OperationDesignerValueSupportedStates.SupportsInPlaceEdit) == OperationDesignerValueSupportedStates.Default)
            {
                return false;
            }
            customInPlaceEdit = typeof(OperationDesignerInPlaceEdit);
            if (row >= this.ElementCount)
            {
                alternateText = string.Empty;
            }
            else if (row != this.insertingIndex)
            {
                object component = this.GetElement(row);
                customInPlaceEdit = this.columns[column].GetInPlaceEdit(component, ref alternateText);
                return (customInPlaceEdit != null);
            }
            return true;
        }

        public SubItemCellStyles ColumnStyles(int column)
        {
            return SubItemCellStyles.Simple;
        }

        protected virtual LabelEditResult CommitLabelEdit(int row, int column, string newText)
        {
            LabelEditResult acceptEdit = LabelEditResult.AcceptEdit;
            int elementCount = this.ElementCount;
            if ((row != this.insertingIndex) && (row < elementCount))
            {
                this.columns[column].SetValue(this.GetElement(row), newText);
                return acceptEdit;
            }
            try
            {
                this.InCreatorNodeCommit = true;
                acceptEdit = this.OnCreatorNodeEditCommitted((this.insertingCreatorIndex == -1) ? (row - elementCount) : this.insertingCreatorIndex, newText, this.insertingIndex);
            }
            finally
            {
                this.InCreatorNodeCommit = false;
            }
            return acceptEdit;
        }

        protected void DoBranchModification(BranchModificationEventArgs modification)
        {
            if (this.onBranchModification != null)
            {
                this.onBranchModification(this, modification);
            }
        }

        public void EndInsert(int index)
        {
            if (this.insertingIndex != -1)
            {
                this.insertingIndex = -1;
                this.insertingCreatorIndex = -1;
            }
        }

        protected virtual VirtualTreeAccessibilityData GetAccessibilityData(int row, int column)
        {
            if (this.columns[column].ColumnIsCheckBox)
            {
                return new VirtualTreeAccessibilityData("{0} {5}", descriptionAccessibilityReplacementFields);
            }
            int elementCount = this.ElementCount;
            if (this.insertingIndex != -1)
            {
                elementCount++;
            }
            if (row >= elementCount)
            {
                return new VirtualTreeAccessibilityData("{1}, {3}", descriptionAccessibilityReplacementFields);
            }
            if (column == 0)
            {
                return new VirtualTreeAccessibilityData("{1}, {3} {0}", descriptionAccessibilityReplacementFields);
            }
            return new VirtualTreeAccessibilityData("{3} {0}", descriptionAccessibilityReplacementFields);
        }

        protected virtual object GetBrowsingObject(int index)
        {
            return this.GetElement(index);
        }

        protected ColumnDescriptor[] GetColumns()
        {
            return this.columns;
        }

        protected virtual string GetCreatorNodeText(int index)
        {
            return string.Empty;
        }

        public virtual CommandID GetDefaultAction(int index)
        {
            return null;
        }

        protected virtual VirtualTreeDisplayData GetDisplayData(int row, int column, VirtualTreeDisplayDataMasks requiredData)
        {
            VirtualTreeDisplayData data = new VirtualTreeDisplayData(-1);
            if ((this.insertingIndex != -1) && (row > this.insertingIndex))
            {
                row--;
            }
            int elementCount = this.ElementCount;
            if (((requiredData.Mask & VirtualTreeDisplayMasks.StateImage) != 0) && (row < elementCount))
            {
                ColumnDescriptor descriptor = this.columns[column];
                if (descriptor.ColumnIsCheckBox)
                {
                    CheckBoxState checkBoxValue = descriptor.GetCheckBoxValue(this.GetElement(row));
                    if (checkBoxValue != CheckBoxState.Unsupported)
                    {
                        data.StateImageIndex = (short) checkBoxValue;
                    }
                }
            }
            if (row >= elementCount)
            {
                data.GrayText = true;
                return data;
            }
            if (((this.lastText != null) && (this.lastText.Length > 0)) && ((this.GetValueSupported(row, column) & OperationDesignerValueSupportedStates.Unsupported) != OperationDesignerValueSupportedStates.Default))
            {
                data.GrayText = true;
            }
            return data;
        }

        public abstract ModelElement GetElement(int index);
        protected virtual IBranch GetExpandedBranch(int index)
        {
            return null;
        }

        public abstract int GetIndexForElement(ModelElement element);
        public int GetJaggedColumnCount(int row)
        {
            if (row < this.ElementCount)
            {
                return this.columns.Length;
            }
            return 1;
        }

        public object GetObject(int row, int column, ObjectStyle style, ref int options)
        {
            switch (((int) style))
            {
                case 0:
                    Microsoft.Internal.Performance.CodeMarkers.Instance.CodeMarker(Microsoft.Internal.Performance.CodeMarkerEvent.perfVSWhitehorseOperationDesignerExpandStart);
                    try
                    {
                        InVirtualTreeEdit = true;
                        IBranch expandedBranch = this.GetExpandedBranch(row);
                        if (expandedBranch != null)
                        {
                            return expandedBranch;
                        }
                    }
                    finally
                    {
                        InVirtualTreeEdit = false;
                    }
                    Microsoft.Internal.Performance.CodeMarkers.Instance.CodeMarker(Microsoft.Internal.Performance.CodeMarkerEvent.perfVSWhitehorseOperationDesignerExpandEnd);
                    break;

                case 1:
                    if (row >= this.ElementCount)
                    {
                        options = 0;
                        break;
                    }
                    return this.GetElement(row);

                default:
                    if ((style == BrowsingObject) && (row < this.ElementCount))
                    {
                        return this.GetBrowsingObject(row);
                    }
                    break;
            }
            return null;
        }

        public object GetService(System.Type serviceType)
        {
            if ((this.columns.Length > 0) && (this.columns[0].Host != null))
            {
                return this.columns[0].Host.GetService(serviceType);
            }
            return null;
        }

        protected virtual string GetText(int row, int column)
        {
            if (this.insertingIndex != -1)
            {
                if (row == this.insertingIndex)
                {
                    return string.Empty;
                }
                if (row > this.insertingIndex)
                {
                    row--;
                }
            }
            int elementCount = this.ElementCount;
            if (row < elementCount)
            {
                object obj2 = this.columns[column].GetValue(this.GetElement(row));
                if (obj2 == null)
                {
                    return string.Empty;
                }
                return obj2.ToString();
            }
            if (column == 0)
            {
                return this.GetCreatorNodeText(row - elementCount);
            }
            return string.Empty;
        }

        protected virtual string GetTipText(int row, int column, ToolTipType tipType)
        {
            if ((tipType == ToolTipType.Default) && (row < this.ElementCount))
            {
                return this.columns[column].GetTipText(this.GetElement(row));
            }
            return null;
        }

        public virtual OperationDesignerValueSupportedStates GetValueSupported(int row, int column)
        {
            OperationDesignerValueSupportedStates supported = OperationDesignerValueSupportedStates.Supported;
            if (this.readOnly)
            {
                return (OperationDesignerValueSupportedStates.SupportsKeyboardNavigation | OperationDesignerValueSupportedStates.Unsupported);
            }
            if (row < this.ElementCount)
            {
                object component = this.GetElement(row);
                return this.columns[column].GetValueSupported(component);
            }
            if (column != 0)
            {
                supported = OperationDesignerValueSupportedStates.Unsupported;
            }
            return supported;
        }

        public virtual bool Initialize(object component, ColumnDescriptor[] columns)
        {
            if (columns == null)
            {
                throw new ArgumentNullException("columns");
            }
            this.columns = columns;
            return true;
        }

        public void InsertCreatorNode(int index, int creatorNodeIndex)
        {
            if (creatorNodeIndex >= this.CreatorNodeCount)
            {
                throw new ArgumentOutOfRangeException("creatorNodeIndex");
            }
            this.insertingIndex = index;
            this.insertingCreatorIndex = creatorNodeIndex;
        }

        protected virtual bool IsExpandable(int index)
        {
            return false;
        }

        public bool IsExpandable(int row, int column)
        {
            if ((column == 0) && (row < this.ElementCount))
            {
                return this.IsExpandable(row);
            }
            return false;
        }

        public LocateObjectData LocateObject(object obj, ObjectStyle style, int locateOptions)
        {
            LocateObjectData locateData = new LocateObjectData(-1, 0, 0);
            switch (style)
            {
                case ObjectStyle.ExpandedBranch:
                case ObjectStyle.SubItemExpansion:
                    locateData.Options = 0;
                    return locateData;

                case ObjectStyle.TrackingObject:
                    return this.LocateTrackingObject(obj, locateData);

                case ObjectStyle.SubItemRootBranch:
                    return locateData;
            }
            return locateData;
        }

        protected virtual LocateObjectData LocateTrackingObject(object tracked, LocateObjectData locateData)
        {
            locateData.Row = -1;
            if (tracked is ModelElement)
            {
                locateData.Row = this.GetIndexForElement((ModelElement) tracked);
            }
            locateData.Options = (locateData.Row >= 0) ? 1 : 0;
            return locateData;
        }

        ProcessKeyResult IOperationDesignerBranch.ProcessKeyDown(int row, int column, KeyEventArgs e)
        {
            if (this.columns[column].AllowKeyDownProcessing(e))
            {
                return this.ProcessKeyDown(row, column, e);
            }
            return new ProcessKeyResult(KeyAction.Process);
        }

        ProcessKeyResult IOperationDesignerBranch.ProcessKeyPress(int row, int column, char key, Keys modifiers)
        {
            if (this.columns[column].AllowKeyPressProcessing(key, modifiers))
            {
                return this.ProcessKeyPress(row, column, key, modifiers);
            }
            return new ProcessKeyResult(KeyAction.Process);
        }

        bool IOperationDesignerInitializeBranch.Initialize(object selection, ColumnDescriptor[] columns)
        {
            return this.Initialize(selection, columns);
        }

        LabelEditResult IBranch.CommitLabelEdit(int row, int column, string newText)
        {
            LabelEditResult result;
            try
            {
                InVirtualTreeEdit = true;
                result = this.CommitLabelEdit(row, column, newText);
            }
            finally
            {
                InVirtualTreeEdit = false;
                if (this.insertingIndex != -1)
                {
                    this.insertingIndex = -1;
                    this.insertingCreatorIndex = -1;
                }
            }
            return result;
        }

        VirtualTreeAccessibilityData IBranch.GetAccessibilityData(int row, int column)
        {
            return this.GetAccessibilityData(row, column);
        }

        VirtualTreeDisplayData IBranch.GetDisplayData(int row, int column, VirtualTreeDisplayDataMasks requiredData)
        {
            return this.GetDisplayData(row, column, requiredData);
        }

        string IBranch.GetText(int row, int column)
        {
            this.lastText = this.GetText(row, column);
            return this.lastText;
        }

        string IBranch.GetTipText(int row, int column, ToolTipType eTipType)
        {
            return this.GetTipText(row, column, eTipType);
        }

        protected virtual LabelEditResult OnCreatorNodeEditCommitted(int index, object value, int insertIndex)
        {
            return LabelEditResult.CancelEdit;
        }

        public virtual void OnDragEvent(object sender, int row, int column, DragEventType eventType, DragEventArgs args)
        {
        }

        public virtual void OnGiveFeedback(GiveFeedbackEventArgs args, int row, int column)
        {
        }

        public virtual void OnQueryContinueDrag(QueryContinueDragEventArgs args, int row, int column)
        {
        }

        public virtual VirtualTreeStartDragData OnStartDrag(object sender, int row, int column, DragReason reason)
        {
            return VirtualTreeStartDragData.Empty;
        }

        protected virtual ProcessKeyResult ProcessKeyDown(int row, int column, KeyEventArgs e)
        {
            ProcessKeyResult result = new ProcessKeyResult();
            result.Action = KeyAction.Process;
            result.Direction = (e.Modifiers != Keys.Shift) ? NavigationDirection.Right : NavigationDirection.Left;
            Keys keyCode = e.KeyCode;
            if (keyCode <= Keys.Space)
            {
                switch (keyCode)
                {
                    case Keys.Tab:
                        result.Action = KeyAction.Handle;
                        result.ColumnType = null;
                        return result;

                    case Keys.Space:
                        if (this.columns[column].ColumnIsCheckBox)
                        {
                            result.Action = KeyAction.Process;
                            return result;
                        }
                        if (this.InLabelEdit)
                        {
                            result.Action = KeyAction.Handle;
                            result.ColumnType = null;
                        }
                        return result;
                }
                return result;
            }
            switch (keyCode)
            {
                case Keys.Up:
                    if (!e.Control)
                    {
                        result.Action = KeyAction.Handle;
                        result.Local = false;
                        result.Direction = NavigationDirection.Up;
                    }
                    return result;

                case Keys.Right:
                    return result;

                case Keys.Down:
                    if (!e.Control)
                    {
                        result.Action = KeyAction.Handle;
                        result.Local = false;
                        result.Direction = NavigationDirection.Down;
                    }
                    return result;
            }
            if (keyCode == Keys.F2)
            {
                result.Action = KeyAction.Handle;
                result.StartLabelEdit = true;
            }
            return result;
        }

        protected virtual ProcessKeyResult ProcessKeyPress(int row, int column, char key, Keys modifiers)
        {
            return new ProcessKeyResult(KeyAction.Process);
        }

        protected virtual void RemoveEventHandlers()
        {
        }

        public StateRefreshChanges SynchronizeState(int row, int column, IBranch matchBranch, int matchRow, int matchColumn)
        {
            return StateRefreshChanges.None;
        }

        public StateRefreshChanges ToggleState(int row, int column)
        {
            try
            {
                InVirtualTreeEdit = true;
                ColumnDescriptor descriptor = this.columns[column];
                if (descriptor.ColumnIsCheckBox)
                {
                    return descriptor.ToggleCheckBoxValue(this.GetElement(row));
                }
            }
            finally
            {
                InVirtualTreeEdit = false;
            }
            return StateRefreshChanges.None;
        }

        public static bool AbortVirtualTreeEdit
        {
            get
            {
                return abortVirtualTreeEdit;
            }
            set
            {
                abortVirtualTreeEdit = value;
            }
        }

        public int ColumnCount
        {
            get
            {
                return this.columns.Length;
            }
        }

        public virtual int CreatorNodeCount
        {
            get
            {
                return 0;
            }
        }

        public abstract int ElementCount { get; }

        protected virtual BranchFeatures Features
        {
            get
            {
                BranchFeatures features = BranchFeatures.ImmediateMouseLabelEdits | BranchFeatures.ExplicitLabelEdits | BranchFeatures.StateChanges | BranchFeatures.InsertsAndDeletes | BranchFeatures.BranchRelocation | BranchFeatures.Expansions;
                if (this.CreatorNodeCount > 0)
                {
                    features |= BranchFeatures.JaggedColumns;
                }
                return features;
            }
        }

        protected bool InCreatorNodeCommit
        {
            get
            {
                return this.inCreatorNodeCommit;
            }
            private set
            {
                this.inCreatorNodeCommit = value;
            }
        }

        protected bool InLabelEdit
        {
            get
            {
                if ((this.columns.Length > 0) && (this.columns[0].Host != null))
                {
                    return this.columns[0].Host.InLabelEdit;
                }
                return false;
            }
        }

        public static bool InVirtualTreeEdit
        {
            get
            {
                return inVirtualTreeEdit;
            }
            set
            {
                inVirtualTreeEdit = value;
            }
        }

        public int ItemCount
        {
            get
            {
                return (this.ElementCount + this.CreatorNodeCount);
            }
        }

        BranchFeatures IBranch.Features
        {
            get
            {
                return this.Features;
            }
        }

        public bool ReadOnly
        {
            get
            {
                return this.readOnly;
            }
            set
            {
                bool readOnly = this.readOnly;
                this.readOnly = value;
                if (readOnly != value)
                {
                    this.DoBranchModification(BranchModificationEventArgs.DisplayDataChanged(new DisplayDataChangedData(this)));
                }
            }
        }

        public int UpdateCounter
        {
            get
            {
                return 0;
            }
        }

        public int VisibleItemCount
        {
            get
            {
                return this.ItemCount;
            }
        }
    }
}

